using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Linq.Expressions;
using viBook.Models;

namespace viBook.Repositories
{
    public class PageRepository : IPageRepository
    {
        viBookContext context = new viBookContext();

        public IQueryable<Page> All
        {
            get { return context.Pages; }
        }

        public IQueryable<Page> AllIncluding(params Expression<Func<Page, object>>[] includeProperties)
        {
            IQueryable<Page> query = context.Pages;
            foreach (var includeProperty in includeProperties)
            {
                query = query.Include(includeProperty);
            }
            return query;
        }

        public Page Find(int id)
        {
            var page = context.Pages.Find(id);
            page.Tags = context.Tags.Where(t => t.PageId == id);
            var chapter = context.Chapters.Find(page.ChapterId);
            if (chapter != null)
            {
                chapter.Book = context.Books.Find(chapter.BookId);
            }
            page.Chapter = chapter;
            var prevPage = context.Pages.FirstOrDefault(p => p.Number == page.Number - 1);
            var nextPage = context.Pages.FirstOrDefault(p => p.Number == page.Number + 1);
            if (nextPage != null)
            {
                page.NextPageId = nextPage.Id;
                page.NextPageUrl = nextPage.ImageSource;
            }
            if (prevPage != null)
            {
                page.PreviousPageId = prevPage.Id;
                page.PreviousPageUrl = prevPage.ImageSource;
            }
            var allOtherPages = context.Pages.Where(p => p.ChapterId == page.ChapterId).OrderBy(p => p.Number);
            page.AllPages = allOtherPages.ToList();
            return page;
        }

        public void InsertOrUpdate(Page page)
        {
            if (page.Id == default(int))
            {
                context.Pages.Add(page);
            }
            else
            {
                context.Entry(page).State = EntityState.Modified;
            }
        }

        public void Delete(int id, out int chapterId)
        {
            var page = context.Pages.Find(id);
            chapterId = page == null ? 0 : page.ChapterId;
            context.Pages.Remove(page);
        }

        public void Delete(int id)
        {
            var listTags = context.Tags.Where(t => t.PageId == id).ToList();
            foreach (var tag in listTags)
            {
                context.Tags.Remove(tag);
                Save();
            }
            var page = context.Pages.Find(id);
            Helpers.Helpers.DeleteFile(page.ImageSource);
            context.Pages.Remove(page);
        }

        public void Save()
        {
            context.SaveChanges();
        }

        public void SaveTags(List<int> deleted, List<Tag> added, int pageId)
        {
            if (deleted != null && deleted.Count > 0)
            {
                foreach (var id in deleted)
                {
                    var tag = context.Tags.Find(id);
                    if (tag != null)
                        context.Tags.Remove(tag);
                }
            }
            if (added != null && added.Count > 0)
            {
                foreach (var tag in added)
                {
                    tag.PageId = pageId;
                    context.Tags.Add(tag);
                }
            }
            context.SaveChanges();
        }

        public void DeletePagesInChapter(int chapterid)
        {
            List<int> listPageId = context.Pages.Where(c => c.ChapterId == chapterid).Select(c => c.Id).ToList();
            foreach (var pageId in listPageId)
            {
                Delete(pageId);
                Save();
            }
        }
    }

    public interface IPageRepository
    {
        IQueryable<Page> All { get; }
        IQueryable<Page> AllIncluding(params Expression<Func<Page, object>>[] includeProperties);
        Page Find(int id);
        void InsertOrUpdate(Page page);
        void Delete(int id, out int chapterId);
        void Delete(int id);
        void Save();
        void SaveTags(List<int> deleted, List<Tag> added, int pageId);
        void DeletePagesInChapter(int chapterid);
    }
}